package com.dap.dao.ha;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.concurrent.atomic.AtomicBoolean;

import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * 数据库心跳检测
 *
 */
public class DBHeartBeat implements Runnable {

    private static Logger LOGGER = LoggerFactory.getLogger(DBHeartBeat.class);
    private static final int MAX_RETRY_COUNT = 3;// 执行检测语句超时的最大重试次数

    private final int timeout;
    private final DataSource ds;
    private final String dataSourceName;
    private final AtomicBoolean fetching;
    private int errorCount;
    private final String validationQuery;


    public DBHeartBeat(DataSource realDatasource, String name, int timeout, String validationQuery) {
        this.ds = realDatasource;
        this.timeout = timeout;
        this.dataSourceName = name;
        this.fetching = new AtomicBoolean(false);
        this.validationQuery = validationQuery;
    }


    @Override
    public void run() {
        Connection newConn = null;
        try {
            newConn = ds.getConnection();
            trySendHeartBeat(newConn);

        } catch (SQLException e) {
            LOGGER.error("DataSource [{}] create socket error - heart beat fail", dataSourceName);
            LOGGER.warn("", e);

            BackendPool.getInstance().removeDataSouce(dataSourceName);
        } finally {
            if (newConn != null) {
                try {
                    newConn.close();
                } catch (SQLException e) {

                }
            }
        }

    }


    /**
     * 链接检测
     * 
     * @param beatConn
     */
    private void trySendHeartBeat(Connection beatConn) {
        if (fetching.compareAndSet(false, true)) {

            Statement st = null;
            try {
                st = beatConn.createStatement();
                st.setQueryTimeout(timeout);
                st.execute(validationQuery);

                BackendPool.getInstance().putDataSouce(dataSourceName, ds);
                LOGGER.debug("DataSource [{}] send heartbeat success !", dataSourceName);
                errorCount = 0;
            } catch (SQLException e) {
                // LOGGER.debug("", e);
                if (MAX_RETRY_COUNT != -1 && ++errorCount < MAX_RETRY_COUNT) {
                    LOGGER.error("DataSource [{}] send heartbeat error but enough, heart beat again",
                        dataSourceName);
                } else {
                    BackendPool.getInstance().removeDataSouce(dataSourceName);
                    LOGGER.debug("DataSource [{}] send heartbeat error !", dataSourceName);
                }
            } finally {
                fetching.set(false);
                if (st != null) {
                    try {
                        st.close();
                    } catch (SQLException e) {
                    }
                }
            }
        } else {
            LOGGER.debug("fetching is true , do not heart beat !");
        }
    }
}
